import json
import unittest
from time import sleep

import re

import requests


# Create your views here.
from django.core.serializers import serialize
from django.template import loader
from django.utils.timezone import now

from cases.models import TeSuite, Steps, InterfaceInfo, Case
from envs.models import Environment
from envs.views import DbUtil
from reports.models import SuitReport, CaseResult, Report, StepResult
from jsonpath_ng import jsonpath, parse
import logging

entype = 'sit'
comparam_dict = {}


def run_test_suits(queryset):
    for q in queryset:
        RunExe().run_suit(q)


def run_test_case(queryset):
    for q in queryset:
        RunExe().run_case(q)


def run_test_step(queryset):
    for q in queryset:
        RunExe().run_step(q,None)
class RunExe:
    def __init__(self):
        self.suit_result = SuitReport()
        self.entype = 'sit'
        self.comparam_dict = {}

    def run_suit(self,test_suit):

        test_cases = test_suit.case.all()
        self.suit_result.test_suit = test_suit
        self.suit_result.start_time = now()
        self.suit_result.save()
        fail_count = 0
        pass_count = 0
        global entype
        global comparam_dict
        entype = test_suit.entype
        case_results = []
        for cs in test_cases:
            case_result=self.run_case(cs)
            if case_result.result_status == 'pass':
                pass_count += 1
            else:
                fail_count += 1
            case_results.append(case_result.get_dict())

        suit_result = SuitReport.objects.get(id=self.suit_result.id)
        suit_result.end_time = now()
        suit_result.fail_count = fail_count
        suit_result.pass_count = pass_count
        suit_result_dict = suit_result.get_dict()
        suit_result_dict['case_results'] = case_results
        html_report = loader.render_to_string('TestReport.html', suit_result_dict)

        suit_result.json_result = suit_result_dict
        suit_result.html_result = html_report
        suit_result.save()

    def run_case(self,cs:Case):
        case_result = CaseResult()
        case_result.start_time = now()
        case_result.test_case = cs
        case_result.end_time = now()
        case_result.save()
        case_result = CaseResult.objects.get(id=case_result.id)
        if self.suit_result.id:
            case_result.case_result_suit = self.suit_result
        steps = cs.steps_set.all()
        if cs.common_param:
            comparam_dict.update(eval(cs.common_param))
        log_text=""
        for step in steps:
            st_res=self.run_step(step,case_result)
            case_result.result_status=st_res.result_status
            log_text = log_text + st_res.log_text
            if case_result.result_status=="fail":
                break
        case_result.end_time = now()
        case_result.log_text=log_text
        case_result.save()
        return case_result

    def run_step(self,step:Steps,cr:CaseResult):
        step_result=StepResult()
        if cr:
            step_result.case_result=cr
        step_result.test_step = step
        step_result.step_description=step.step_description
        step_result.operation_type=step.operation_type
        step_result.log_text="{}  ***开始执行步骤:{}".format(str(now()), step.step_description)+'\n'
        logging.info("{}  开始执行步骤{}".format(str(now()), step.step_description))

        if step.common_param:
            self.comparam_dict.update(eval(step.common_param))
        try:

            step_result = ExEngine(step, self.comparam_dict,step_result).switchEngine()
            self.comparam_dict = get_common_param(step, step_result.response_header, step_result.response_body, self.comparam_dict)
            step_result=self.verifyResult(step_result,step,self.comparam_dict)
            step_result.log_text =step_result.log_text + "{}  ***步骤执行结束:{}".format(str(now()), step.step_description) + '\n'
            logging.info("{}  ***步骤执行结束:{}".format(str(now()), step.step_description))

        except Exception as e:
            step_result.result_status='fail'
            step_result.log_text = step_result.log_text+str(e)+'\n'
            step_result.log_text = step_result.log_text + "{}  ***步骤执行异常:{}".format(str(now()), step.step_description) + '\n'
            logging.error("{}  ***步骤执行异常:{}".format(str(now()), step.step_description))
            logging.error("**异常信息为:{}".format(str(e)))
        step_result.save()


        return step_result

    def verifyResult(self,step_restut: StepResult, step:Steps, comparam_dict: dict):

        status = ""
        sourceData=step_restut.response_body
        vs=step.verifyResults.all()
        if not vs:
            return "pass", "此步骤无断言"

        assert_result=[]
        for i in vs:
            actualPath = i.actualPath
            expected_result = ParamReplace(i.exceptValue, comparam_dict).get_new_var()
            actualValue = JsonParam(actualPath, eval(sourceData)).get_value()
            exceptValue = expected_result
            rule = i.rule
            i.actualValue=actualValue

            logging.info("期望值是{},实际值是{}".format(exceptValue, actualValue))
            if rule == 'eq':
                if str(actualValue) == exceptValue:
                    status = "pass"
                    step_restut.log_text =step_restut.log_text+"期望值是{},实际值是{},验证通过".format(exceptValue, actualValue)+'\n'
                    logging.info("期望值是{},实际值是{},验证通过".format(exceptValue, actualValue))
                else:
                    status = "fail"
                    step_restut.log_text = step_restut.log_text +"实际值是：{},与期望值：{}不符，验证不通过,".format(actualValue,exceptValue)+'\n'
                    logging.info("实际值是：{},与期望值：{}不符，验证不通过,".format(actualValue,exceptValue))
                    break
            elif rule == 'ct':
                if actualValue.find(exceptValue) > 0:
                    status = "pass"
                    step_restut.log_text = step_restut.log_text + "实际值：{},包含期望值：{},验证通过".format(actualValue, exceptValue) + '\n'
                    logging.info("实际值：{},包含期望值：{},验证通过".format(actualValue, exceptValue))
                else:
                    status = "fail"
                    step_restut.log_text = step_restut.log_text + "实际值：{},未包含期望值：{},验证不通过".format(actualValue, exceptValue)+'\n'
                    logging.info("实际值：{},未包含期望值：{},验证不通过".format(actualValue, exceptValue))
                    break
            i.status=status

            assert_result.append(i.to_dict())
        step_restut.assert_result=str(assert_result)
        step_restut.result_status=status
        return step_restut


def get_common_param(step,res_header,result,comparam_dict):
    rsps = step.resultParamGets.all()
    if rsps:
        for i in rsps:
            if i.area=='header':
                comparam_dict[i.storeValue] = JsonParam(i.valuePath, result).get_value()
            elif i.area=='body':
                comparam_dict[i.storeValue] = JsonParam(i.valuePath, res_header).get_value()
    return comparam_dict




class ExEngine():
    def __init__(self, step: Steps,comparam_dict,step_result:StepResult):
        self.step = step
        self.sql_script = step.sql_name
        # self.db_info = step.sql_name.db_info
        self.inter_info = step.interface_name
        self.comparam_dict=comparam_dict
        self.stepResult=step_result
        # self.client= requests()

    def switchEngine(self):
        if self.step.operation_type == 'http':
            return self.httpEngine()
        elif self.step.operation_type == 'db':
            return self.dbEngine()

    def getUrl(self):
        sysEnv = Environment.objects.filter(entype=entype).get(system_name__interfaceinfo__id=self.inter_info.id)
        if not self.step.ip:
            print(sysEnv.ip)
            self.step.ip = sysEnv.ip
        if not self.step.port:
            print(self.inter_info.id, entype)
            self.step.port = sysEnv.port
        if not self.step.port:
            self.step.port = 8080
        url = self.step.ip + ":" + self.step.port  + self.inter_info.path
        url = ParamReplace(url, self.comparam_dict).get_new_var()
        return url

    def get_req_json(self):
        req_json = eval(self.inter_info.request_body)
        print(type(self.step.replace_param))
        print(self.step.replace_param)
        if self.step.is_use_temp and self.step.replace_param:
            for key, value in eval(self.step.replace_param).items():
                req_json = JsonParam(key, req_json).replace_param(value)
        req_json = ParamReplace(req_json, self.comparam_dict).get_new_var()

        return req_json

    def get_req_header(self):
        inter_request_header={}
        if self.inter_info.request_header:
            inter_request_header = eval(self.inter_info.request_header)
        if self.step.request_header:
            step_request_header = eval(self.step.request_header)
            inter_request_header.update(step_request_header)

        request_header = ParamReplace(inter_request_header, self.comparam_dict).get_new_var()

        return request_header

        # 发送请求
    def send_interface(self,  url,method, header, data):
        print(url, header, data)

        if method == "POST":
            res = requests.post(url, json=data, headers=header, verify=False)
        elif method == "GET":
            if header:
                header = eval(header)
            res = requests.get(url,params=data,headers=header, verify=False)
        elif method == "PUT":
            res = requests.post(url, json=data, headers=header, verify=False)
        elif method == "DELETE":
            res = requests.post(url, json=data, headers=header, verify=False)
        return res
    def httpEngine(self):
        # return {
        #     'post': requests.post(url=inter, data=json.dumps(data), headers=header),
        #     'put': requests.put(url=url, data=json.dumps(data), **kwargs),
        #     'delete': requests.delete(url=url, data=json.dumps(data), **kwargs),
        #     'get': requests.get(url=url, params=params, headers=header),
        # }.get(step.operation_type, None)()
        req_header=self.get_req_header()
        req_json=self.get_req_json()
        url=self.getUrl()
        logging.info("正在执行http请求：  " + url)
        logging.info("正在执行请求方式：  " + self.inter_info.method)
        logging.info("正在执行请求header： " + str(req_header))
        logging.info("正在执行请求body： " + str(req_json))
        self.stepResult.url=url
        self.stepResult.method=self.inter_info.method
        self.stepResult.request_header=req_header
        self.stepResult.request_body=req_json
        try:
            res = self.send_interface(self.getUrl(), self.inter_info.method, req_header, req_json)
            res_header, res_json = res.headers, json.loads(res.text)
            self.stepResult.response_header=res_header
            self.stepResult.response_body=str(res_json)
        except Exception as e:
            print(str(e))
        logging.info("返回的响应header： " + str(res_header))
        logging.info("返回的响应body： " + str(res_json))
        return self.stepResult

    def dbEngine(self):
        s = []
        global comparam_dict
        exe_sql = self.sql_script.sql_content
        exe_sql = ParamReplace(exe_sql, comparam_dict).get_new_var()
        self.stepResult.sql_content=exe_sql
        self.stepResult.sql_type=self.sql_script.sql_type
        self.stepResult.db_info=self.sql_script.db_info
        logging.info("正在执行数据库操作" + exe_sql)
        try:
            if self.sql_script.sql_type == "DQL":
                s = DbUtil(self.sql_script.db_info).get_all(self.sql_script.sql_content)
                logging.info(s)
            else:
                s = DbUtil(self.sql_script.db_info).execu_sql(self.sql_script.sql_content)
                logging.info(s)
        except Exception as e:
            print(str(e))
            self.stepResult.log_text=self.stepResult.log_text+str(e)+'\n'
        self.stepResult.response_body=s
        return self.stepResult


class JsonParam:
    def __init__(self, jsonpath, jsondata):
        self.jsonpath_expr = parse(jsonpath)
        self.jsondata = jsondata

    def replace_param(self, new_value):
        new_jondata = None
        if self.jsonpath_expr.find(self.jsondata):
            new_jondata = self.jsonpath_expr.update(self.jsondata, new_value)
        return new_jondata

    def get_value(self):
        key_value = None
        if self.jsonpath_expr.find(self.jsondata):
            key_value = [match.value for match in self.jsonpath_expr.find(self.jsondata)][0]
        return key_value


class ParamReplace:
    def __init__(self, content, comparam_dict: dict):
        self.content = content
        self.comparam_dict = comparam_dict

    def get_new_var(self):
        var_list = self.extract_variables(self.content)
        # 检查是否存在变量
        if var_list:
            for var_name in var_list:
                var_value = self.comparam_dict[var_name]
                self.content = self.replace_var(self.content, var_name, var_value)
        return self.content

    # 替换内容中的变量, 返回字符串型
    def replace_var(self, content, var_name, var_value):
        if not isinstance(content, str):
            content = json.dumps(content)
        var_name = "${" + var_name+"}"
        content = content.replace(str(var_name), str(var_value))
        return content

    # 从内容中提取所有变量名, 变量格式为$variable,返回变量名list
    def extract_variables(self, content):
        variable_regexp = r"\$\{([\w_]+)\}"
        if not isinstance(content, str):
            content = str(content)
        try:
            return re.findall(variable_regexp, content)
        except TypeError:
            print(121)
        return []
